/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "nci_format.h"

#define PA_RATS_HIS_OFFSET 4
#define PB_ATTRIB_HI_LAYER_OFFSET 1

static void fmt_specific_params_poll_a(uint8_t* p, tNCI_RF_TECH_PARAM_PA *pa) {

    STREAM_TO_ARRAY(pa->sens_res, p, NCI_SENS_RES_LEN);
    STREAM_TO_UINT8(pa->nfcid1_len, p);
    STREAM_TO_ARRAY(pa->nfcid1, p, pa->nfcid1_len);

    uint8_t sel_res_len = 0;

    STREAM_TO_UINT8(sel_res_len, p);

    if (sel_res_len == 1) {
        STREAM_TO_UINT8(pa->sel_res, p);
    }

    STREAM_TO_UINT8(pa->hr_length, p);
    STREAM_TO_ARRAY(pa->hr, p, pa->hr_length);
}

static void fmt_specific_params_poll_b(uint8_t *p, tNCI_RF_TECH_PARAM_PB *pb) {
    STREAM_TO_UINT8(pb->sensb_res_len, p);
    STREAM_TO_ARRAY(pb->sensb_res, p, pb->sensb_res_len);
}

static void fmt_specific_params_poll_f(uint8_t *p, tNCI_RF_TECH_PARAM_PF *pf) {
    STREAM_TO_UINT8(pf->bit_rate, p);
    STREAM_TO_UINT8(pf->sensf_res_len, p);
    STREAM_TO_ARRAY(pf->sensf_res, p, pf->sensf_res_len);
}

static void fmt_specific_params_poll_v(uint8_t *p, tNCI_RF_TECH_PARAM_PV *pv) {
    STREAM_TO_UINT8(pv->res_flag, p);
    STREAM_TO_UINT8(pv->dsfid, p);
    STREAM_TO_ARRAY(pv->uid, p, NCI_TECH_PARAM_PV_UID_LEN);
}

static void fmt_specific_params_listen_b(uint8_t *p, tNCI_RF_TECH_PARAM_LB *lb) {
    STREAM_TO_UINT8(lb->sensb_req, p);
}

static void fmt_specific_params_listen_f(uint8_t *p, tNCI_RF_TECH_PARAM_LF *lf) {
    uint8_t nfcid2_len;
    STREAM_TO_UINT8(nfcid2_len, p);
    STREAM_TO_ARRAY(lf->nfcid2, p, nfcid2_len);
}

static void fmt_activation_params_isodep_poll_a(uint8_t *p, tNCI_RF_ACT_PARAM_PA_ISO_DEP *pa) {
    STREAM_TO_UINT8(pa->rats_response_len, p);
    STREAM_TO_ARRAY(pa->rats_response, p, pa->rats_response_len);

    if (pa->rats_response_len <= PA_RATS_HIS_OFFSET) {
        pa->his_bytes_len = 0;
    } else {
        pa->his_bytes_len = pa->rats_response_len - PA_RATS_HIS_OFFSET;
        pa->his_bytes = &pa->rats_response[PA_RATS_HIS_OFFSET];
    }
}

static void fmt_activation_params_isodep_listen_a(uint8_t *p, tNCI_RF_ACT_PARAM_LA_ISO_DEP *la) {
    STREAM_TO_UINT8(la->rats_command, p);
}

static void fmt_activation_params_isodep_poll_b(uint8_t *p, tNCI_RF_ACT_PARAM_PB_ISO_DEP *pb) {
    STREAM_TO_UINT8(pb->attrib_res_len, p);
    STREAM_TO_ARRAY(pb->attrib_res, p, pb->attrib_res_len);

    if (pb->attrib_res_len > PB_ATTRIB_HI_LAYER_OFFSET) {
        pb->hi_layer_len = pb->attrib_res_len - PB_ATTRIB_HI_LAYER_OFFSET;
        pb->hi_layer_bytes = &pb->attrib_res[PB_ATTRIB_HI_LAYER_OFFSET];
    }
}

static void fmt_activation_params_isodep_listen_b(uint8_t *p, tNCI_RF_ACT_PARAM_LB_ISO_DEP *lb) {
    STREAM_TO_UINT8(lb->attrib_req_len, p);
    STREAM_TO_ARRAY(lb->attrib_req, p, lb->attrib_req_len);
}

tNCI_STATUS nci_fmt_discover_ntf(uint8_t *data, uint16_t data_len, tNCI_RF_DISCOVER_PARAMS *params) {
    (void) data_len;
    uint8_t *p = data;

    STREAM_TO_UINT8(params->id, p);
    STREAM_TO_UINT8(params->protocol, p);
    STREAM_TO_UINT8(params->tech_mode, p);

    uint8_t specific_params_len = 0;

    STREAM_TO_UINT8(specific_params_len, p);

    switch (params->tech_mode)
    {
    case NCI_RF_TECH_A_PASSIVE_POLL_MODE:
        fmt_specific_params_poll_a(p, &params->tech_params.pa);
        break;
    case NCI_RF_TECH_B_PASSIVE_POLL_MODE:
        fmt_specific_params_poll_b(p, &params->tech_params.pb);
        break;
    case NCI_RF_TECH_F_PASSIVE_POLL_MODE:
        fmt_specific_params_poll_f(p, &params->tech_params.pf);
        break;
    case NCI_RF_TECH_V_PASSIVE_POLL_MODE:
        fmt_specific_params_poll_v(p, &params->tech_params.pv);
        break;
    default:
        NFCLOG_E("Unknown RF technology mode: %d", params->tech_mode);
        return NCI_STATUS_SYNTAX_ERROR;
    }

    p += specific_params_len;

    uint8_t notification_type;

    STREAM_TO_UINT8(notification_type, p);

    params->is_last = (notification_type == 0);

    return NCI_STATUS_OK;
}

tNCI_STATUS nci_fmt_intf_activation_ntf(uint8_t *data, uint16_t data_len, tNCI_RF_INTF_ACTIVATED_PARAMS *params) {
    (void) data_len;
    uint8_t *p = data;

    STREAM_TO_UINT8(params->id, p);
    STREAM_TO_UINT8(params->interface, p);
    STREAM_TO_UINT8(params->protocol, p);
    STREAM_TO_UINT8(params->activation_tech_mode, p);
    STREAM_TO_UINT8(params->max_data_packet_payload_size, p);
    STREAM_TO_UINT8(params->initial_number_of_credits, p);

    uint8_t tech_specific_params_len;

    STREAM_TO_UINT8(tech_specific_params_len, p);

    switch (params->activation_tech_mode)
    {
    case NCI_RF_TECH_A_PASSIVE_POLL_MODE:
        fmt_specific_params_poll_a(p, &params->tech_params.pa);
        break;
    case NCI_RF_TECH_A_PASSIVE_LISTEN_MODE:
        // do nothing
        break;
    case NCI_RF_TECH_B_PASSIVE_POLL_MODE:
        fmt_specific_params_poll_b(p, &params->tech_params.pb);
        break;
    case NCI_RF_TECH_B_PASSIVE_LISTEN_MODE:
        fmt_specific_params_listen_b(p, &params->tech_params.lb);
        break;
    case NCI_RF_TECH_F_PASSIVE_POLL_MODE:
        fmt_specific_params_poll_f(p, &params->tech_params.pf);
        break;
    case NCI_RF_TECH_F_PASSIVE_LISTEN_MODE:
        fmt_specific_params_listen_f(p, &params->tech_params.lf);
        break;
    case NCI_RF_TECH_V_PASSIVE_POLL_MODE:
        fmt_specific_params_poll_v(p, &params->tech_params.pv);
        break;
    case NCI_RF_TECH_ACTIVE_POLL_MODE:
        break;
    case NCI_RF_TECH_ACTIVE_LISTEN_MODE:
        break;
    default:
        NFCLOG_E("unknown RF technology mode: %d", params->activation_tech_mode);
        return NCI_STATUS_SYNTAX_ERROR;
    }

    p += tech_specific_params_len;

    STREAM_TO_UINT8(params->data_exchange_tech_mode, p);
    STREAM_TO_UINT8(params->data_exchange_transmit_bit_rate, p);
    STREAM_TO_UINT8(params->data_exchange_receive_bit_rate, p);

    uint8_t activation_params_len;
    STREAM_TO_UINT8(activation_params_len, p);
    (void) activation_params_len; // 暂时无用

    if (params->protocol == NCI_RF_PROTOCOL_ISO_DEP) {
        switch (params->activation_tech_mode)
        {
        case NCI_RF_TECH_A_PASSIVE_POLL_MODE:
            fmt_activation_params_isodep_poll_a(p, &params->act_params.pa_iso_dep);
            break;
        case NCI_RF_TECH_A_PASSIVE_LISTEN_MODE:
            fmt_activation_params_isodep_listen_a(p, &params->act_params.la_iso_dep);
            break;
        case NCI_RF_TECH_B_PASSIVE_POLL_MODE:
            fmt_activation_params_isodep_poll_b(p, &params->act_params.pb_iso_dep);
            break;
        case NCI_RF_TECH_B_PASSIVE_LISTEN_MODE:
            fmt_activation_params_isodep_listen_b(p, &params->act_params.lb_iso_dep);
            break;
        default:
            NFCLOG_E("Unknown RF technology mode: %d", params->activation_tech_mode);
            return NCI_STATUS_SYNTAX_ERROR;
        }
    } else if (params->protocol == NCI_RF_PROTOCOL_NFC_DEP) {
        // TODO
        switch (params->activation_tech_mode)
        {
        case NCI_RF_TECH_ACTIVE_POLL_MODE:
            break;
        case NCI_RF_TECH_ACTIVE_LISTEN_MODE:
            break;
        default:
            break;
        }
    }

    return NCI_STATUS_OK;
}
